package com.tools.web.interceptor.auth._common;

import com.tools.common.object.Note;
import com.tools.common.object.json.JsonKit;
import com.tools.common.thread.Timeunit;
import com.tools.middle.redis.client.JedisPlus;
import com.tools.web.interceptor.auth.*;

import java.util.Map;
import java.util.Objects;

/**
 * JedisPlus 客户端操作 Redis 实现的 “用户多在线记录” 的 AuthenticationManager 身份认证拦截器
 */
@Note("JedisPlus 客户端操作 Redis 实现的 “用户多在线记录” 的 AuthenticationManager 身份认证拦截器")
public abstract class JedisPlusMultipleAuthenticationManager extends GenericAuthenticationManager implements MultipleRedisLuaScript {

    @Note("操作 Redis 的 JedisPlus 客户端，依靠 Jedis 实现")
    private final JedisPlus jedisPlus;

    protected JedisPlusMultipleAuthenticationManager(JedisPlus jedisPlus, AuthSource source, AuthUserService authUserService) {
        super(source, authUserService);
        this.jedisPlus = Objects.requireNonNull(jedisPlus, "操作 Redis 的 JedisPlus 客户端为 null");
    }

    @Override
    public final Timeunit getTimeunitUsedBySubclass() {
        return Timeunit.SECOND;
    }

    @Override
    protected GetAuthUserResult getAuthUser(String key, AuthToken decryptedAuthToken) {
        try {
            String loginDeviceType = decryptedAuthToken.getLoginDeviceType();
            String uuid = decryptedAuthToken.getUuid();
            String authUserKey = super.getMultipleAuthUserSaveKey(key);
            String tokenKey = super.getMultipleLoginRecordSaveKey(key, loginDeviceType, uuid);
            Object result = this.jedisPlus.eval(GET_AUTH_USER, 2, tokenKey, authUserKey);
            if (result == null) return super.protected_getResultIfExpired(decryptedAuthToken);
            String json = result.toString();
            MultipleAuthUser authUser = JsonKit.toEntity(json, MultipleAuthUser.class);
            authUser.setLoginDeviceType(loginDeviceType);
            authUser.setUuid(uuid);
            authUser.setLoginUserType(decryptedAuthToken.getLoginUserType());
            return new GetAuthUserResult(true, authUser);
        } finally {
            this.jedisPlus.close();
        }
    }

    @Override
    protected void setAuthUser(String key, AuthUser srcAuthUser, AuthToken decryptedAuthToken) {
        try {
            String loginDeviceType = decryptedAuthToken.getLoginDeviceType();
            Map<String, Integer> loginDeviceTypeAndMaxOnlineTotal = super.getLoginDeviceTypeAndMaxOnlineTotal();
            int maxSize = (loginDeviceTypeAndMaxOnlineTotal != null && !loginDeviceTypeAndMaxOnlineTotal.isEmpty())
                    ? loginDeviceTypeAndMaxOnlineTotal.get(loginDeviceType)
                    : 0;
            String deviceKeyPrefix = super.getMultipleDeviceSavePrefix(key, loginDeviceType);
            String tokenKey = super.getMultipleLoginRecordSaveKey(key, loginDeviceType,
                    decryptedAuthToken.getUuid());
            long loginTime = System.currentTimeMillis();
            String authUserKey = super.getMultipleAuthUserSaveKey(key);
            String authUserValue = JsonKit.toJSON(srcAuthUser);
            long expirationMill = decryptedAuthToken.getExpirationMill();
            long expiration = this.getTimeunitUsedBySubclass().cast(expirationMill, Timeunit.MILL);
            this.jedisPlus.eval(SET_AUTH_USER, 0,
                    deviceKeyPrefix, maxSize, tokenKey, loginTime,
                    expiration, authUserKey, authUserValue);
        } finally {
            this.jedisPlus.close();
        }
    }

    @Override
    protected void removeAuthUser(String key) {
        try {
            this.jedisPlus.eval(REMOVE_AUTH_USER, 0, key);
        } finally {
            this.jedisPlus.close();
        }
    }

    @Override
    protected void updateAuthUser(String key, AuthUser newAuthUser) {
        try {
            String authUserKey = super.getMultipleAuthUserSaveKey(key);
            String json = (String) this.jedisPlus.get(authUserKey);
            if(json == null) return;
            MultipleAuthUser oldAuthUser = JsonKit.toEntity(json, MultipleAuthUser.class);
            newAuthUser.copyAuthData(oldAuthUser);
            newAuthUser.copyCustomData(oldAuthUser);
            Object user = newAuthUser.getUser();
            oldAuthUser.setUser(user);
            String authUserValue = JsonKit.toJSON(oldAuthUser);
            this.jedisPlus.eval(UPDATE_AUTH_USER, 0, authUserKey, authUserValue);
        } finally {
            this.jedisPlus.close();
        }
    }

    @Override
    protected void protected_loginOut(String key, String loginDeviceType, String uuid) {
        try {
            String tokenKey = super.getMultipleLoginRecordSaveKey(key, loginDeviceType, uuid);
            String authUserKey = super.getMultipleAuthUserSaveKey(key);
            this.jedisPlus.eval(LOGIN_OUT, 0, tokenKey, key, authUserKey);
        } finally {
            this.jedisPlus.close();
        }
    }
}
